package com.dycx.food.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dycx.common.SerialNumberUtil;
import com.dycx.common.context.UserInfo;
import com.dycx.common.context.UserInfoContext;
import com.dycx.food.constants.MallConstants;
import com.dycx.food.converter.OrderConverter;
import com.dycx.food.converter.OrderGoodsConverter;
import com.dycx.food.dto.OrderCreateDTO;
import com.dycx.food.dto.OrderDTO;
import com.dycx.food.dto.OrderGoodsDTO;
import com.dycx.food.dto.ShoppingCartDTO;
import com.dycx.food.entity.GoodsDO;
import com.dycx.food.entity.GoodsMainDO;
import com.dycx.food.entity.OrderDO;
import com.dycx.food.entity.OrderGoodsDO;
import com.dycx.food.enums.OrderGoodsStatusEnum;
import com.dycx.food.enums.OrderStatusEnum;
import com.dycx.food.mapper.OrderFoodMapper;
import com.dycx.food.service.*;
import com.dycx.food.vo.OrderGoodsVO;
import com.dycx.food.vo.OrderVO;
import com.dycx.payment.enums.PayTypeEnum;
import com.dycx.user.service.SellerService;
import com.dycx.user.service.UserService;
import com.dycx.user.vo.SellerVO;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class OrderFoodImpl extends ServiceImpl<OrderFoodMapper, OrderDO> implements OrderFoodService {

    private OrderFoodMapper orderMapper;
    private OrderGoodsFoodService orderGoodsService;
    private GoodsFoodService goodsService;
    private GoodsMainFoodService goodsMainService;
    private UserService userService;
    private SellerService sellerService;
    private ShoppingCartFoodService shoppingCartFoodService;

    @Resource
    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 添加
     *
     * @param orderDto
     * @return
     */
    @Override
    public String createOrder(OrderCreateDTO orderDto) {
        UserInfo userInfo = UserInfoContext.get();

        SellerVO sellerVO = sellerService.getSellerInfoByUid(userInfo.getUserId());

        // 商品信息
        List<OrderGoodsDO> goodsList = new ArrayList<>();
        int totalMoney = 0;
        int totalGoodsNum = 0;
        // 用于删除购物车
        List<Integer> idList = new ArrayList<>();

        for (ShoppingCartDTO item : orderDto.getGoodsParam()) {
            if (ObjectUtil.isNotEmpty(item.getId())) {
                idList.add(item.getId());
            }

            GoodsDO goodsDO = goodsService.getById(item.getGoodsId());
            Assert.notNull(goodsDO, "商品不存在");

            if (goodsDO.getGoodsStorage() < item.getGoodsNum()) {
                throw new RuntimeException("商品【" + goodsDO.getGoodsName() + "】库存不足，暂不支持下单");
            }

            if (goodsDO.getGoodsPrice() <= 0 || goodsDO.getGoodsVipPrice() <= 0) {
                throw new RuntimeException("商品【" + goodsDO.getGoodsName() + "】无价格，暂不支持下单");
            }

            if (!goodsDO.getIsShelf()) {
                throw new RuntimeException("商品【" + goodsDO.getGoodsName() + "】已下架，暂不支持下单");
            }

            //是否为批发商
            if (ObjectUtil.isNotEmpty(sellerVO) && userInfo.getUserId() > 0) {
                goodsDO.setGoodsPrice(goodsDO.getGoodsVipPrice());
            }

            int goodsMoney = goodsDO.getGoodsPrice() * item.getGoodsNum();

            totalMoney += goodsMoney;
            totalGoodsNum += item.getGoodsNum();

            OrderGoodsDO orderGoodsDO = BeanUtil.toBean(goodsDO, OrderGoodsDO.class);
            orderGoodsDO.setGoodsNum(item.getGoodsNum());
            orderGoodsDO.setTotalMoney(goodsMoney);
            orderGoodsDO.setGoodsId(goodsDO.getId());
            orderGoodsDO.setRemark(item.getRemark());
            orderGoodsDO.setStatus(OrderGoodsStatusEnum.WAITING.getCode());
            goodsList.add(orderGoodsDO);
        }

        //创建订单号
        String orderNo = SerialNumberUtil.createFoodOrderNo();

        String key = "SerialNumber:FoodOrderNo:" + LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMMdd");
        String queueNumber = stringRedisTemplate.opsForValue().get(key);
        assert queueNumber != null;

        //添加订单
        OrderDO orderDO = new OrderDO();
        orderDO.setOrderNo(orderNo);
        orderDO.setOrderName(goodsList.get(0).getGoodsName());

        orderDO.setQueueNumber(Integer.parseInt(queueNumber));
        orderDO.setTotalMoney(totalMoney);
        orderDO.setTotalGoodsNum(totalGoodsNum);
        orderDO.setGoodsMoney(totalMoney);
        orderDO.setOrderStatus(OrderStatusEnum.UNPAID.getCode());
        orderDO.setUid(userInfo.getUserId());
        orderDO.setCreateTime(LocalDateTime.now());
        orderDO.setRemark(orderDto.getRemark());

        if (!this.save(orderDO)) {
            throw new RuntimeException("添加订单失败");
        }

        //添加订单商品
        for (OrderGoodsDO orderGoodsDO : goodsList) {
            orderGoodsDO.setOrderNo(orderNo);

            if (!orderGoodsService.save(orderGoodsDO)) {
                throw new RuntimeException("添加订单商品失败");
            }
        }

        //更新商品库存
        this.updateGoodsSalesAndStorage(BeanUtil.toBean(orderDO, OrderVO.class), MallConstants.NUMBER_POSITIVE);

        //删除购物车
        if (idList.size() > 0) {
            shoppingCartFoodService.delCartByIds(idList);
        }

        orderDto.setOrderNo(orderNo);
        return orderNo;
    }

    /**
     * 分页
     *
     * @return
     */
    @Override
    public Page<OrderVO> getPage(OrderDTO dto) {
        LambdaQueryWrapper<OrderDO> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(ObjectUtil.isNotNull(dto.getOrderStatus()), OrderDO::getOrderStatus, dto.getOrderStatus());

        if (OrderStatusEnum.UNPAID.getCode().equals(dto.getOrderStatus())) {
            wrapper.orderByAsc(OrderDO::getId);
        } else {
            wrapper.orderByDesc(OrderDO::getId);
        }

        Page<OrderDO> entityPage = page(new Page<>(dto.getPageIndex(), dto.getPageSize()), wrapper);
        Page<OrderVO> voPage = OrderConverter.entityToVoPage(entityPage);

        for (OrderVO orderVO : voPage.getRecords()) {
            //用户端是否显示取消订单按钮
            if (OrderStatusEnum.UNPAID.getCode().equals(orderVO.getOrderStatus())) {
                orderVO.setShowCancelBtn(true);
            }

            if (dto.getIsQueryGoodsList()) {
                LambdaQueryWrapper<OrderGoodsDO> queryGoodsWrapper = new LambdaQueryWrapper<>();
                queryGoodsWrapper.eq(OrderGoodsDO::getOrderNo, orderVO.getOrderNo());
                List<OrderGoodsDO> orderGoodsDOList = orderGoodsService.list(queryGoodsWrapper);
                orderVO.setGoodsList(OrderGoodsConverter.entityToVoList(orderGoodsDOList));
            }
        }

        return voPage;
    }

    /**
     * 根据订单号查询订单信息
     *
     * @param orderNo 订单号
     * @return
     */
    @Override
    public OrderVO getOrderDetailByOrderNo(String orderNo, Boolean queryGoodsList, Boolean queryUser) {
        LambdaQueryWrapper<OrderDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderDO::getOrderNo, orderNo);

        OrderDO orderDO = this.getOne(queryWrapper);

        OrderVO orderVO = BeanUtil.toBean(orderDO, OrderVO.class);

        //是否查询商品详情
        if (queryGoodsList) {
            LambdaQueryWrapper<OrderGoodsDO> queryGoodsWrapper = new LambdaQueryWrapper<>();
            queryGoodsWrapper.eq(OrderGoodsDO::getOrderNo, orderNo);

            List<OrderGoodsDO> orderGoodsDOList = orderGoodsService.list(queryGoodsWrapper);

            List<OrderGoodsVO> orderGoodsVOList = orderGoodsDOList.stream().map(item ->
                    BeanUtil.toBean(item, OrderGoodsVO.class)
            ).collect(Collectors.toList());

            orderVO.setGoodsList(orderGoodsVOList);
        }

        if (queryUser) {
            orderVO.setUserInfo(userService.load(orderVO.getUid()));
            orderVO.setSellerInfo(sellerService.getSellerInfoByUid(orderVO.getUid()));
        }

        orderVO.setPayTypeName(PayTypeEnum.converter(orderVO.getPayType()));

        return orderVO;
    }

    @Override
    public OrderVO getOrderDetailByOrderNo(String orderNo) {
        return this.getOrderDetailByOrderNo(orderNo, false, false);
    }

    /**
     * 取消订单
     *
     * @param orderNo 订单号
     * @return
     */
    @Override
    public Boolean cancelOrder(String orderNo) {
        OrderVO orderVO = this.getOrderDetailByOrderNo(orderNo);
        Assert.notNull(orderVO, "未查询到订单信息");

        if (orderVO.getOrderStatus().equals(OrderStatusEnum.COMPLETE.getCode())) {
            throw new RuntimeException("当前状态不正确，不能取消订单");
        }

        //更新商品库存
        this.updateGoodsSalesAndStorage(orderVO, MallConstants.NUMBER_MINUS);

        OrderDO orderDO = new OrderDO();
        orderDO.setId(orderVO.getId());
        orderDO.setOrderStatus(OrderStatusEnum.CANCEL.getCode());

        return this.updateById(orderDO);
    }

    /**
     * 完成订单
     *
     * @param orderNo 订单号
     * @return
     */
    @Override
    public Boolean completeOrder(String orderNo) {
        OrderVO orderVO = this.getOrderDetailByOrderNo(orderNo);
        Assert.notNull(orderVO, "未查询到订单信息");

        if (!orderVO.getOrderStatus().equals(OrderStatusEnum.UNPAID.getCode())) {
            throw new RuntimeException("当前状态不正确，不能完成");
        }

        OrderDO orderDO = new OrderDO();
        orderDO.setId(orderVO.getId());
        orderDO.setOrderStatus(OrderStatusEnum.COMPLETE.getCode());
        orderDO.setCompleteTime(LocalDateTime.now());

        return this.updateById(orderDO);
    }

    /**
     * 更新商品库存和销量
     *
     * @param orderVO 订单
     * @param numType 更新类型
     */
    public void updateGoodsSalesAndStorage(OrderVO orderVO, int numType) {
        LambdaQueryWrapper<OrderGoodsDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderGoodsDO::getOrderNo, orderVO.getOrderNo());
        List<OrderGoodsDO> orderGoodsList = orderGoodsService.list(wrapper);

        for (OrderGoodsDO item : orderGoodsList) {
            int goodsNum = item.getGoodsNum() * numType;

            //更新子商品销量和库存
            GoodsDO goodsDO = goodsService.getById(item.getGoodsId());
            goodsDO.setSales(goodsDO.getSales() + goodsNum);
            goodsDO.setGoodsStorage(goodsDO.getGoodsStorage() - goodsNum);
            goodsService.updateById(goodsDO);

            //更新公共商品销量和库存
            GoodsMainDO goodsMainDO = goodsMainService.getById(goodsDO.getMainGoodsId());
            goodsMainDO.setSales(goodsMainDO.getSales() + goodsNum);
            goodsMainDO.setGoodsStorage(goodsMainDO.getGoodsStorage() - goodsNum);
            goodsMainService.updateById(goodsMainDO);
        }
    }

    /**
     * 修改备注
     *
     * @param
     * @return
     */
    @Override
    public Boolean updateServiceRemark(OrderDTO orderDTO) {
        LambdaQueryWrapper<OrderDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderDO::getOrderNo, orderDTO.getOrderNo());

        OrderDO order = new OrderDO();
        order.setServiceRemark(orderDTO.getServiceRemark());
        return this.update(order, wrapper);
    }

    @Override
    public Boolean orderGoodsStatusEnd(Integer orderGoodsId) {
        OrderGoodsDO orderGoodsDO = new OrderGoodsDO();
        orderGoodsDO.setId(orderGoodsId);
        orderGoodsDO.setStatus(OrderGoodsStatusEnum.END.getCode());
        if (!orderGoodsService.updateById(orderGoodsDO)) throw new RuntimeException("修改状态失败");

        orderGoodsDO = orderGoodsService.getById(orderGoodsId);

        LambdaQueryWrapper<OrderGoodsDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderGoodsDO::getOrderNo, orderGoodsDO.getOrderNo());
        List<OrderGoodsDO> orderGoodsDOList = orderGoodsService.list(wrapper);

        boolean allComplete = true;
        for (OrderGoodsDO entity : orderGoodsDOList) {
            if (OrderGoodsStatusEnum.WAITING.getCode().equals(entity.getStatus())) {
                allComplete = false;
            }
        }

        if (allComplete) {
            LambdaUpdateWrapper<OrderDO> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(OrderDO::getOrderStatus, OrderStatusEnum.COMPLETE.getCode());
            updateWrapper.eq(OrderDO::getOrderNo, orderGoodsDO.getOrderNo());
            update(updateWrapper);
        }

        return true;
    }

    @Override
    public Boolean orderGoodsStatusComplete(Integer orderGoodsId) {
        OrderGoodsDO orderGoodsDO = new OrderGoodsDO();
        orderGoodsDO.setId(orderGoodsId);
        orderGoodsDO.setStatus(OrderGoodsStatusEnum.COMPLETE.getCode());
        return orderGoodsService.updateById(orderGoodsDO);
    }
}
